package com.abel;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * 模拟动态代理类Proxy
 */
public class MyProxy {
	public static Object getInstance(Object target) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
		//获取目标对象的直接接口
		Class clazz = target.getClass().getInterfaces()[0];
		String interfaceName = clazz.getSimpleName();
		String content = "";
		String line = "\n";
		String tab = "\t";
		//包名
		String packageContent = "package com.baidu;" + line;
		//import部分
		String importContent = "import " + clazz.getName() + ";" + line;
		//类第一行
		String clazzFirstLineContent = "public class $MyProxy implements " + interfaceName + "{" + line;
		//目标接口作为成员变量
		String filedContent = tab + "private " + interfaceName + " target;" + line;
		//构造器
		String constructorContent = tab + "public $MyProxy (" + interfaceName + " target) {" + line
				+ tab + tab + "this.target = target;" + line
				+ tab + "}" + line;

		//方法
		String methodContent = "";
		Method[] methods = clazz.getDeclaredMethods();

		for (Method method : methods) {
			String returnTypeName = method.getReturnType().getSimpleName();
			String methodName = method.getName();
			Class args[] = method.getParameterTypes();
			String argsContent = "";
			String paramsContent = "";
			int flag = 0;
			//定义参数及参数名
			for (Class arg : args) {
				String temp = arg.getSimpleName();
				argsContent += temp + " p" + flag + ",";
				paramsContent += "p" + flag + ",";
				flag++;
			}
			//去掉尾部的逗号
			if(argsContent.length() > 0) {
				argsContent = argsContent.substring(0, argsContent.lastIndexOf(",") - 1);
				paramsContent = paramsContent.substring(0, paramsContent.lastIndexOf(",") - 1);
			}
			//编写代理类方法，在里面调用原对象的query()方法
			//public String query(String p0){
			//		System.out.println("log");
			//		target.query(p0);
			//}
			methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsContent + ") {" + line
					+ tab + tab + "System.out.println(\"log\");" + line
					+ tab + tab + "target." + methodName + "(" + paramsContent + ");" + line
					+ tab + "}" + line;
		}
		//将所有字符串组装成一个.java文件的内容
		content += packageContent + importContent + clazzFirstLineContent + filedContent + constructorContent + methodContent + "}";

		//在对应目录创建一个.java文件
		File file = new File("d:\\com\\baidu\\$MyProxy.java");
		//将字符串写入.java文件中
		try {
			if (!file.exists()) {
				file.createNewFile();
			}

			FileWriter fw = new FileWriter(file);
			fw.write(content);
			fw.flush();
			fw.close();
		} catch (Exception e) {
		}

		//将.java文件编译生成.class文件
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
		Iterable units = fileMgr.getJavaFileObjects(file);
		JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
		t.call();
		try {
			fileMgr.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//将.class文件加载进来，并创建实例返回
		URL[] urls = new URL[]{new URL("file:D:\\\\")};
		URLClassLoader urlClassLoader = new URLClassLoader(urls);
		Class cls = urlClassLoader.loadClass("com.baidu.$MyProxy");
		Constructor constructor = cls.getConstructor(clazz);
		Object o  = constructor.newInstance(target);
		return o;
	}
}
